<?php
/**
 * Поле базы данных
 * 
 * Класс одного поля в базе
 * @author Anton Zavidov
 * @package myLiveShop
 */
import('core.validator');
/**
 * Класс для работы с полем
 *
 */
class Field extends Base {
	/**
	 * Тип поля число
	 *
	 */
	const TYPE_INT='int';
	/**
	 * Тип поля строка
	 *
	 */
	const TYPE_STRING='varchar';
	/**
	 * Тип поля текст
	 *
	 */
	const TYPE_TEXT='text';
	/**
	 * Тип поля дата
	 *
	 */
	const TYPE_DATE='date';
	/**
	 * Тип поля дата и время
	 *
	 */
	const TYPE_DATETIME='datetime';
	/**
	 * Тип поля пользовательский
	 *
	 */
	const TYPE_CUSTOMIZED='customized';
	
	/**
	 * Ссылка на класс модели
	 *
	 * @var Model
	 */
	public $model;
	
	/**
	 * Имя поля
	 *
	 * @var sting
	 */
	private $name;
	/**
	 * Имя таблицы в базе
	 *
	 * @var string
	 */
	private $table;
	/**
	 * Join запрос
	 *
	 * @var string
	 */
	private $join;
	/**
	 * Тип поля
	 *
	 * @var string
	 */
	private $type=self::TYPE_INT;
	/**
	 * Длинна поля
	 *
	 * @var int
	 */
	private $lenght=9;
	/**
	 * Значение по умолчанию
	 *
	 * @var mixed
	 */
	private $default_value=0;
	/**
	 * Тип данных для валидации
	 *
	 * @var  string
	 */
	public $validate_type=Validator::VALIDATE_INT;
	/**
	 * Calback для валидатора
	 *
	 * @var array
	 */
	private $validate_callback;
	/**
	 * Имя поля
	 *
	 * @var string
	 */
	private $fields=false;
	/**
	 * Запрос для поля
	 *
	 * @var string
	 */
	private $field_query=null;
	/**
	 * Текущее значение поля
	 *
	 * @var mixed
	 */
	private $value=null;
	/**
	 * Флаг указывающий на успешную валидацию
	 *
	 * @var boolean
	 */
	private $validated=null;
	/**
	 * Флаг указывающий на обязательное заполнение этого поля
	 *
	 * @var boolean
	 */
	private $important=false;
	/**
	 * Флаг указывающий на то что это поле автоматически заполняется базой
	 *
	 * @var boolean
	 */
	private $auto=false;
	/**
	 * Флаг указывающий на то что это поле искуственное (не существующее в базе)
	 *
	 * @var boolean
	 */
	private $custom=false;
	/**
	 * Таблица которая стыкуется по этому полю
	 *
	 * @var string
	 */
	private $join_table;	
	/**
	 * Поле в join таблице через которое идёт связка
	 *
	 * @var string
	 */
	private $join_field;
	/**
	 * Конструктор
	 *
	 * @param Model $model ссылка на модель
	 * @param string $name имя поля
	 * @param string $table имя таблицы
	 * @param array $params настроечнве параметры
	 */
	public function __construct(&$model,$name,$table,$params=array()){
		$this->model = $model;
		$this->name=$name;
		$this->table=$table;
		$varlist=get_object_vars($this);
		foreach ($params as $key=>$item) {
			$key=trim($key);
			if(array_key_exists($key,$varlist))$this->$key=$item;
			else{
				new CoreExeption('Попытка задать несуществующую переменную '.$key.' в обекте Field',E_WARNING,__FILE__,__LINE__,array('value'=>$item));
			}
			switch ($key) {
				case 'join_table':
					if(!isset($params['join_field']))$this->join_field=$name;
					break;
				case 'join_field':
					if(!isset($params['join_table'])){
						if(!strpos($params['join_field'],DOT)) new CoreExeption('Неправильно задана привязка к join таблице '.$key.' в обекте Field. Используйте [имя наблицы].[имя поля]',E_WARNING,__FILE__,__LINE__,array('value'=>$item));
						else{
							$join=explode(DOT,$item);
							$this->join_table=$join[0];
							$this->join_field=$join[1];
						}
					}
					break;
				case 'type':
					if(!isset($params['validate_type'])){
						$this->validate_type=Validator::defaultValidator($item);
					}
					if($item==self::TYPE_TEXT){
					    $this->lenght=0;
					}
					break;
				case 'field_query':
					if(!isset($params['custom'])){
						$this->custom=true;
					}
					break;
				default:
					break;
			}
		}
		if(!$this->fields)$this->fields=$name;
		//тестируем поля и их соответствие типам
		Validator::typeTest($this);
		
		parent::__construct(__CLASS__.' ('.$name.')');
	}
	/**
	 * получение значения переменных поля
	 *
	 * @param string $name имя переменной
	 * @return mixed значение
	 */
	public function _($name){
		if($name=='value')return $this->value();
		return isset($this->$name)?$this->$name:null;
	}
	/**
	 * получение sql поля
	 *
	 * @return string значение
	 */
	public function fieldName(){
		//если есть специальный запрос
		if($this->field_query) return '('.$this->field_query.') AS `'.$this->name.'`';
		
		return '`'.$this->table.'`.`'.$this->name.'`';
	}
	/**
	 * Валидация
	 *
	 * @param mixed $value данные
	 * @return mixed true или текст ошибки
	 */
	public function validate($value){
		$this->erase();
		$this->validated=import('core.validator',true)->_($value,$this);
		if($this->validated===true){
			$this->value=$value;
			return true;
		}
		return $this->validated;
	}
	/**
	 * получаем значение поля
	 *
	 * @param mixed $value данные
	 * @param boolean $noValidate флаг указывающий на то что данные не нужно валидировать
	 * @return mixed
	 */
	public function value($value=null,$noValidate=false){
		if($value!==null){
			//обновляем поля
			$this->erase();
			//если не надо валидировать
			if($noValidate){
				//$this->validated=true;
				$this->value=$value;
				return $this->value;
			}else{
				//если валидация прошла успешно возвращаем переменную
				if($this->validate($value)===true){
					return $this->value;
				}else{
					return false;
				}
			}
		}
		//если данные не преданы и ввалидация успешна то возвращаем переменную
		if ($this->validated===true) {
			return $this->value;
		}
		//иначе возвращаем значение по умолчанию
		return $this->default_value;
	}
	/**
	 * Обнуляем значение поля
	 *
	 */
	public function erase(){
		$this->value=null;
		$this->validated=null;
	}
	/**
	 * Перед сохранением проверка значения поля
	 *
	 * @return mixed true если всё в порядке, или текст ошибки
	 */
	public function preSave($noValidate=false){
	    if($noValidate)$this->validated=true;
		//если значение установленно
		if($this->value || $this->value===0){
		    //pr($this);
			//если ещё не валидировалось
			if($this->validated===null){
				//валидируем
				return $this->validate($this->value);
			}else{
				//ec();
				//возвращаем результат предыдущей валидации
				return $this->validated;
			}
		}elseif($this->important){
			//если поле обязательно для заполнения то выдаём ошибку потому как оно не заполненно
			if($this->validated!==null && $this->validated!==true)return $this->validated;
			if(!$this->auto)return 'Поле должно быть заполненным';
			return true;
		}elseif($this->auto){
			//если поле может быть заполненно базой то пропукаем его
			$this->validated=true;
			return true;
		}else{
			//ставим ему значение по умолчанию
			$this->value=$this->default_value;
			$this->validated=true;
			return true;
		}
	}
	
}